package Utile;


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author PanJiaWen
 * @version 1.0
 * @date: 2022/5/20 17:10
 * @comment
 */
public final class BaseDao {
    public static final String DRIVER = "oracle.jdbc.driver.OracleDriver";
    public static final String JDBCURL = "jdbc:oracle:thin:@127.0.0.1:1521/orcl";
    public static final String USER = "kz";
    public static final String PASSWORD = "root";
    private static Connection conn;
    private static PreparedStatement preState;
    private static ResultSet resultSet;

    static {
        try {
            Class.forName(DRIVER);
            conn = DriverManager.getConnection(JDBCURL
                    , USER, PASSWORD);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    private BaseDao() {

    }


    public static void close() {

        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (preState != null) {
            try {
                preState.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @param sql  SQL语句
     * @param args 参数
     * @return
     */
    public static int doUpdate(String sql, Object... args) {
        int result = 0;
        try {
            preState = conn.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                preState.setObject(i + 1, args[i]);
            }
            result = preState.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return result;
    }

    public static List<Map<String, Object>> doQuery(String sql, Object... args) {
        List<Map<String, Object>> list = new ArrayList<>();
        try {
            preState = conn.prepareStatement(sql);
            for (int i = 1; i <= args.length; i++) {
                preState.setObject(i, args[i]);
            }
            resultSet = preState.executeQuery();
            ResultSetMetaData rsmd = resultSet.getMetaData();
            // 获取表中列的数量（ResultSet对象中的列数）
            int cols = rsmd.getColumnCount();
            // 5.遍历结果集
            while (resultSet.next()) {
                Map<String, Object> map = new HashMap<>(cols);
                for (int i = 1; i <= cols; i++) {
                    String colName = rsmd.getColumnName(i);
                    Object colValue = resultSet.getObject(colName);
                    if (colValue == null) {
                        colValue = "";
                    }
                    map.put(colName, colValue);
                }
                list.add(map);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return list;
    }

    public static <T> List<T> doQuery(Class<T> cls, String sql, Object... args) {
        List<T> list = new ArrayList<>();
        try {
            preState = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                preState.setObject(i + 1, args[i]);
            }
            resultSet = preState.executeQuery();
            Constructor<T> constructor = cls.getConstructor();
            Field[] fields = cls.getDeclaredFields();
            // 获得表结构（用于获取ResultSet对象中列的类型和属性的信息的对象。如字段数、字段名等等）
            ResultSetMetaData rsmd = resultSet.getMetaData();
            // 获取表中列的数量（ResultSet对象中的列数）
            int cols = rsmd.getColumnCount();
            while (resultSet.next()) {
                T t = constructor.newInstance();
                for (int i = 1; i <= cols; i++) {
                    String colName = rsmd.getColumnName(i);
                    Object colValue = resultSet.getObject(colName);
                    for (Field field : fields) {
                        if (colValue == null) {
                            break;
                        }
                        String fname = field.getName();
                        if (fname.toUpperCase().equals(colName.replaceAll("_", ""))) {
                            //暴力反射
                            field.setAccessible(true);
                            colValue = handleValue(colValue, field);
                            System.out.println(getTypeName(colValue));
                            field.set(t, colValue);
                            break;
                        }
                    }
                }
                list.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return list;
    }

    private static Object handleValue(Object o, Field field) {
        if (o == null) {
            return o;
        }
        System.out.println(getTypeName(o));
        if (o instanceof BigDecimal) {
            String str=field.getType().getSimpleName();
            if ("Integer".equals(str)) {
                o = Integer.valueOf(((BigDecimal) o).intValue());
            }else if("Float".equals(str)){
                o = Float.valueOf(((BigDecimal) o).floatValue());
            }
        }

        return o;
    }

    public static void openTransaction(){
        try {
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

    private static void closeTransaction(){
        try {
            conn.setAutoCommit(true);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void commit(){
        try {
            conn.commit();
            closeTransaction();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void rollback(){
        try {
            conn.rollback();
            closeTransaction();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private static String getTypeName(Object o) {
        if (o == null) {
            return null;
        }
        return o.getClass().getTypeName();
    }
}
